/*
 * Description: 通信服务端基类，实现了服务端的基础通信功能。接口类。
 */
#include <csignal>
#include <iostream>
#include <algorithm>
#include "log.h"
#include "link_base.h"
#include "guest_socket.h"
#include "service.h"

using namespace std;

namespace COMMON {
Service::Service(const std::string &name) : m_name(name)
{
}

Service::~Service()
{
}

void Service::Dispatch(Guest::protobuf::link::Call &call, Guest::protobuf::link::Result &res,
                       const std::string &clientInfo)
{
    LOG_DEBUG("Service::Dispatch!");
    (void)clientInfo;
    Dispatch(call, res);
}

// 分发client端事件，如果同步并返回结果
void DispatchAndReply(Guest::protobuf::link::Call call, Service *service, int messageType,
    const std::shared_ptr<MsgSock> &msgSock)
{
    LOG_DEBUG("Service::DispatchAndReply");
    if (service == nullptr || msgSock == nullptr) {
        return;
    }
    Guest::protobuf::link::Result result;
    // 把调用传递给dispatch,并且获取返回值
    service->Dispatch(call, result, msgSock->GetSockInfo().remoteAddr.strAddr);
    // 同步call才需要写回去返回值
    if (messageType == static_cast<int>(MessageType::SYNC_CALL)) {
        result.set_callid(call.callid());
        // 返回值发送回去
        auto ret = service->SendMessage(msgSock, MessageType::RESPONSE, result);
        if (ret != OK) {
            LOG_ERR("send result failed, errno:" FORMAT(d), GetLastError());
        }
    }
}

// 处理client端发过来的事件
void Service::HandleEvent(const std::shared_ptr<MsgSock> &msgSock, void *arg)
{
    LOG_DEBUG("Service::HandleEvent");
    auto service = static_cast<Service *>(arg);
    if (service == nullptr) {
        return;
    }
    std::vector<char> messageBuffer;
    MessageType messageType = MessageType::INIT_TYPE;

    if (LinkBase::ReceiveMessage(msgSock, messageType, messageBuffer) != OK) {
        LOG_ERR("service handle event, recv msg failed!");
        return;
    }

    // 解析出返回值
    Guest::protobuf::link::Call call;
    call.ParseFromArray(messageBuffer.data(), static_cast<int>(messageBuffer.size()));

    // 管理service的生命周期
    if (call.async()) {
        (void) service->m_threadPool.Enqueue(DispatchAndReply, call, service, static_cast<int>(messageType), msgSock);
    } else {
        DispatchAndReply(call, service, static_cast<int>(messageType), msgSock);
    }
}


void Service::OnConnected(const std::string &connectName)
{
    (void)connectName;
}

void Service::OnDisconnected(const std::string &connectName)
{
    (void)connectName;
}

void Service::ConnectEventNotify(const std::string &connectName, const std::shared_ptr<MsgSock> &subServer)
{
    LOG_DEBUG("Service::ConnectEventNotify");
    if (connectName.empty() || subServer == nullptr) {
        return;
    }
    m_sockMap[subServer->GetSockInfo().sockFd] = connectName;
    this->OnConnected(connectName);
}

int Service::CloseEventServer()
{
    if (m_msgSerialSock != nullptr) {
        return m_msgSerialSock->Close();
    }
    return 0;
}

// client端连接模式
bool Service::HandleConnectMode(const std::shared_ptr<MsgSock> &subServer, void *arg, const std::string &mode,
                                const std::string &name) const
{
    LOG_DEBUG("Service::HandleConnectMode");
    auto service = static_cast<Service *>(arg);
    if (service == nullptr) {
        LOG_ERR("service handle connect mode, server is null");
        return false;
    }
    if (mode.find(GUEST_EVENT) != std::string::npos) {
        HandleEvent(subServer, arg);
        service->ConnectEventNotify(name, subServer);
    } else {
        LOG_WARN("service handle connect mode: " FORMAT(s) " error", mode.c_str());
        return false;
    }
    return true;
}

// 处理client事件
void Service::HandleEventTask(const std::shared_ptr<MsgSock> &subServer, void *arg) const
{
    LOG_DEBUG("Service::HandleEventTask");
    while (true) {
        auto serviceTmp = static_cast<Service *>(arg);
        if (serviceTmp == nullptr) {
            return;
        }
        std::vector<char> messageBufferTmp;
        MessageType messageTypeTmp = MessageType::INIT_TYPE;

        if (LinkBase::ReceiveMessage(subServer, messageTypeTmp, messageBufferTmp) != OK) {
            LOG_ERR("HandleEventTask, recv msg failed!");
            return;
        }

        // 解析出返回值
        Guest::protobuf::link::Call call;
        call.ParseFromArray(messageBufferTmp.data(), static_cast<int>(messageBufferTmp.size()));

        // serviceTmp
        (void)serviceTmp->m_threadPool.Enqueue(
            DispatchAndReply, call, serviceTmp, static_cast<int>(messageTypeTmp), subServer);
    }
}

// serial type连接成功的回调
void Service::HandleConnectSerial(const std::shared_ptr<MsgSock> &server, void *arg)
{
    LOG_DEBUG("Service::HandleConnectSerial");
    if (server == nullptr) {
        return;
    }
    auto serialSubServer = server->AcceptEx();
    if (serialSubServer == nullptr) {
        return;
    }
    auto serialService = static_cast<Service *>(arg);
    if (serialService == nullptr) {
        return;
    }
    std::vector<char> messageBuffer;
    MessageType messageType = MessageType::INIT_TYPE;
    constexpr uint32_t timeout = 3; // 连接成功后接收等待超时3s

    if (LinkBase::ReceiveMessage(serialSubServer, messageType, messageBuffer, timeout) != OK) {
        LOG_ERR("HandleConnectSerial, recv msg failed!");
        return;
    }

    Guest::protobuf::link::Handshake handshake;
    handshake.ParseFromArray(messageBuffer.data(), static_cast<int>(messageBuffer.size()));

    LOG_DEBUG("HandleConnectSerial, connectionmode = " FORMAT(s), handshake.connectionmode().c_str());
    LOG_DEBUG("HandleConnectSerial, clientname = " FORMAT(s), handshake.clientname().c_str());
    if (!serialService->HandleConnectMode(serialSubServer, arg, handshake.connectionmode(), SERIAL_CLIENT_NAME)) {
        return;
    }
    /* 默认-1: 阻塞 */
    if (serialService->m_curTimeout != DEFAULT_TIME_OUT) {
        serialSubServer->SetRecvTimeout(serialService->m_curTimeout);
        serialService->m_curTimeout = DEFAULT_TIME_OUT;
    }

    if (handshake.connectionmode().find(GUEST_EVENT) != std::string::npos) {
        serialService->HandleEventTask(serialSubServer, arg);
    }
}

void Service::SetReadTimeout(int timeout)
{
    m_curTimeout = timeout;
}

int Service::SendMessage(const std::shared_ptr<MsgSock> &msgSock, MessageType type,
    const google::protobuf::MessageLite &message) const
{
    LOG_DEBUG("Service::SendMessage");
    return LinkBase::SendMessage(msgSock, type, message);
}

int Service::EstablishEventServer(int port,
    const std::string& userId, const std::string& appId, const std::string& vmName)
{
    LOG_DEBUG("Service::EstablishEventServer");
    std::unique_lock<std::mutex> lk(m_initLock);
    SocketInfo info { userId, appId, vmName, port };
    if (CreateServer(info, m_msgSerialSock) != OK) {
        return CREATE_SERVER_FAILED;
    }
    return OK;
}

int Service::CreateServer(SocketInfo info, std::shared_ptr<MsgSock> &msgSock)
{
    LOG_DEBUG("create server: " FORMAT(d) ", server: " FORMAT(s), info.port,
              m_name.c_str());
    std::shared_ptr<MsgSock> tempSock= nullptr;
    try {
        tempSock= std::make_unique<MsgSock>();
    } catch (const std::exception &e) {
        LOG_ERR("make unique error!");
        return INIT_MSGSOCK_FAILED;
    }
    if (tempSock->Create(info) != OK) {
        return MSGSOCK_CREATE_FAILED;
    }

    msgSock = std::move(tempSock);

    m_threadPool.Enqueue(HandleConnectSerial, msgSock, static_cast<void *>(this));
    return OK;
}

void Service::ParseProto(google::protobuf::MessageLite &target, Guest::protobuf::link::Call &call)
{
    if (!(target).ParseFromString((call).parameters())) {
        LOG_ERR("Transacted parameters parse error!");
    }
}
}
